<!DOCTYPE html>
<html lang="zn-ch">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>2048小游戏</title>
<link rel="stylesheet" href="./static/css/bootstrap.min.css">
<style>
.center{text-align: center;}   
.area{box-sizing: border-box;margin:1rem auto;}
.area .col-xs-3{border:1px solid #ddd;height:6rem;width:6rem;box-sizing: border-box;} 
.item{line-height: 6rem;font-size:8rem;color:white;padding:0;}
.container{min-height:100vh;}
.start{margin:.5rem;}
.msg{color:red;}
</style>
</head>
<body class="container">
<div class="row center">
    <h3>2048 小游戏</h3>
</div>

<div class="row center">
    得分：<span class="count">0</span>
    历史最高：<span class="top">0</span>
</div>
<div class="row center">
    <button class="btn btn-default start">重新开始</button>
</div>
<div class="row center">
    <button class="btn btn-default goback">上一步</button>
    <span class="step"></span>
    <button class="btn btn-default gonext">下一步</button>
    
</div>
<div class="row center area">

</div>

<div class="row msg center"></div>

    
</body>
</html>
<script src="./static/js/jquery.min.js"></script>
<script src="./static/js/localdb.js"></script>

<script>


var fun={
    rand:function(min,max){
       return parseInt(Math.random()*(max-min))+min;
    },
    get_color:function(){
       var index=this.rand(0,config.bgcolor.length-1);
       return config.bgcolor[index];
    },
    get_all:function(){
       var all=[];
       $(".item").each(function(){
           var n=$(this).text();
           all.push(n?n:0);
       })
       return all;
    },
    cache:function(key,value){
        if(!value){
            return JSON.parse(localStorage.getItem(key));
        }else{
           localStorage.setItem(key,JSON.stringify(value));
        }
    },
    set_empty:function(){
      config.empty_item=[];
      var i=0;
      $(".item").each(function(){
          var n=$(this).text();
          if(!n){
              config.empty_item.push(i);
          }
          i++;
      })
      if(config.empty_item.length<2){
         this.finish();
      }
    },
    finish:function(){
        db.insert("score_2048",{time:new Date().getTime(),score:config.score})
    },
    is_finish:function(){
       var len=$(".item").length;
       var arr=[];
       for(var i=0;i<len;i++){
           var n=$(".item").eq(i).text();
           if(n){
               arr.push(n);
           }else{
               $(".msg").text("");
               return false;
           }
       }
       for(var j=0;j<len;j++){
          if(j%config.row!=(config.row-1)){
              if(arr[j]==arr[j+1]){
                 $(".msg").text("");
                 return false;
              }
          }
          if(j<(len-config.row)){
            //   console.log(arr[j],arr[j+config.row]);
            if(arr[j]==arr[j+config.row]){
                $(".msg").text("");
                return false;
            }
         }
       }
       $(".msg").text("游戏结束");
       return true;
    },
    async:function(fn){
      setTimeout(function(){
          fn();
      },0)
    },
    get_empty:function(){
        var index=this.rand(0,config.empty_item.length-1);
        var item=config.empty_item[index];
        config.empty_item.splice(index,1);
        return item;
    },
    next:function(isinit){
        this.set_bg();
        this.set_empty();
        var all_item=this.get_all();
        if(JSON.stringify(all_item)!=JSON.stringify(config.all_item)){
            this.set_num();
            this.clear_history();
            config.history.push(this.get_all());
            config.his_index++;
            if(!isinit){
                this.cache("history_2048",config.history);
            }
            $(".step").text("第"+(config.his_index)+"步");
        }
    },
    clear_history:function(){
        var len=config.history.length;
      if(len>config.his_index+1){
          for(var i=config.his_index+1;i<len;i++){
              config.history.pop();
          }
      }
    },
    show_history:function(isback){
        var len=config.history.length;
        if(isback){
            config.his_index--;
        }else{
            config.his_index++;
        }
        if(config.his_index<1){
            config.his_index=1;
            alert("不能再退了");
            return;
        }else if(config.his_index>len-1){
            config.his_index=len-1;
            alert("不能再前进了");
            return;
        }
        // console.log(config.his_index,len,config.history);
        $(".step").text("第"+(config.his_index)+"步");
        this.draw(config.history[config.his_index]);
    },
    set_num:function(){
        var empty=fun.get_empty();
        var style={background:config.bgcolor[0]};
        $(".item").eq(empty).text(2).css(style);
    },
    merge:function(arr,isright){
        if(arr.length<2){return arr;}
        var len=arr.length;
        var old_len=len;
        if(isright){
            for(var i=0;i<len;i++){
                var index=len-1-i;
                if(index-1>=0&&arr[index]==arr[index-1]){
                    arr[index]=2*arr[index];
                    arr.splice(index-1,1);
                    len--;
                    i--;
                }
            }
        }else{
            for(var i=0;i<len;i++){
                if(i+1<len&&arr[i]==arr[i+1]){
                    arr[i]=2*arr[i];
                    arr.splice(i+1,1);
                    len--;
                    i--;
                }
            }
        }
     
        if(arr.length<old_len){
            this.merge(arr);
        }
        return arr;
    },
    copy:function(arr){
        var re=[];
        arr.forEach(function(item){
            re.push(item);
        })
        return re;
    },
    arr_pad:function(arr,len,isright){
       var arr_len=arr.length;
       var empty_len=len-arr_len;
       for(var i=0;i<empty_len;i++){
           if(isright){
               arr.unshift("");
           }else{
               arr.push("");
           }
       }
       return arr;
    },
    set_bg:function(){
        var num=[];
        var count=0;
        $(".item").each(function(){
            var n=$(this).text();
            $(this).css({background:"white"});
            if(n){
                count+=parseInt(n);
                if(num.indexOf(n)==-1){
                    num.push(n);
                }
            }
        })
        num.sort(function(a,b){
            return a-b;
        })
        var color={};
        for(var i=0,len=num.length;i<len;i++){
            color[num[i]]=config.bgcolor[i];
        }
        $(".item").each(function(){
            var n=$(this).text();
            if(n){
                var size=config.fontSize/(n.toString().length)+"rem";
                $(this).css({background:color[n],fontSize:size});
            }else{
                $(this).css({fontSize:config.fontSize+"rem"});
            }
        })
        config.score=count;
        $(".count").text(count);
    },
    draw:function(arr){
        var len=arr.length;
        for(var i=0;i<len;i++){
            $(".item").eq(i).text(arr[i]>0?arr[i]:"");
        }
        this.set_bg();
    },
    get_top:function(){
      var score=db.max('score_2048',"score");
      $(".top").text(score);
    },
    init:function(){
        config.history=[];
        config.his_index=-1;
        var len=config.row*config.row;
        var str="";
        for(var i=0;i<len;i++){
            str+='<div class="col-xs-3 item"></div>';
        }
        $(".area").html(str);
        $(".msg").text("");
        var r=config.row*6+"rem";
        $(".area").css({
            width:r,
            height:r
            });
        this.get_top();
        fun.next(true);
        fun.next(true);
    }
}


var config={
    all_item:[],
    empty_item:[],
    score:0,
    bgcolor:['#ddd',"#999","#FFEFD5","#FFE4B5","#98F5FF","#00F5FF","#9AFF9A","#00FF7F","#00BFFF","#0000FF","#8470FF","#696969","#8B658B","#FFA500","#FF4040","#FF0000"],
    row:4,
    fontSize:8,
    history:[],
    his_index:-1,
}

var controller={
    toLeft:function(isright){
        var i=0;
        var arr=[];
        var row=config.row;
        var maxindex=row-1;
        config.all_item=fun.get_all();
        $(".item").each(function(){
          var index=i%row;
          if(index==0){
              arr=[];
          }
          var n=$(this).text();
          if(n){arr.push(n);}
          if(index==maxindex){
              fun.merge(arr,isright);
              fun.arr_pad(arr,row,isright);
              for(var j=0;j<row;j++){
                     $(".item").eq(i-maxindex+j).text(arr[j]);
              }
          }
          i++;
      })
      fun.next();
    },
    toRight:function(){
        controller.toLeft(true);
    },
    toUp:function(isright){
        var arr=[];
        var row=config.row;
        var i=0;
        config.all_item=fun.get_all();
        $(".item").each(function(){
            var num=$(this).text();
            if(i<row){
                arr[i]=[];
            }
            if(num){
                 arr[i%row].push(num); 
            }
          i++;
        })

        for(var j=0;j<row;j++){
            var tem=arr[j];
            fun.merge(tem,isright);
            fun.arr_pad(tem,row,isright);
            for(var ii=0;ii<row;ii++){
                $(".item").eq(row*ii+j).text(tem[ii]);
            }
        }
      fun.next();
    },
    toDown:function(){
        controller.toUp(true);
    }
}


$(".goback").click(function(){
    fun.show_history(true);
})
$(".gonext").click(function(){
    fun.show_history();
})


fun.init();
if(fun.cache("history_2048")){
    config.history=fun.cache("history_2048");
    config.his_index=config.history.length-2;
    fun.show_history();
}


$(".start").click(function(){
    fun.init();
    $(".msg").text("");
})

window.onkeydown=function(e){
    if(fun.is_finish()){return;}
    if(e.keyCode==37){
        controller.toLeft();
    }else if(e.keyCode==38){
        controller.toUp();
    }else if(e.keyCode==39){
        controller.toRight();
    }else if(e.keyCode==40){
        controller.toDown();
    }
}

function slide(){
    var down={};
    var up={};
    var min=30;
    var event_type="";
    $("body").on("touchstart",function(e){
        if(fun.is_finish()){return;}
        var edata=e.originalEvent.changedTouches[0];
        down={x:edata.clientX,y:edata.clientY};
    })

    $("body").on("touchmove",function(e){
        e.preventDefault(); //阻止滚动
    })
    
    $("body").on("touchend",function(e){
        if(fun.is_finish()){return;}
        var edata=e.originalEvent.changedTouches[0];
        up={x:edata.clientX,y:edata.clientY};
        var x=up.x-down.x;
        var y=up.y-down.y;
        var x_count=Math.abs(x);
        var y_count=Math.abs(y);
        if(x_count<=min&&y_count<=min){return;}
        if(x_count>=y_count){
            event_type=x>0?"toRight":"toLeft";
        }else{
            event_type=y>0?"toDown":"toUp";
        }
        controller[event_type]();
        haddo=true;
    })
    
   
}
slide();


</script>